/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "sha256.h"

#include "local_net_def.h"
#include "local_net_udp.h"
#include "local_net_communication.h"
#include "local_net_utils.h"

#ifdef L0_DEVICE
#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "lwip/ip4_addr.h"
#elif defined(L2_DEVICE)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <fcntl.h>
#include <string.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#endif

/**
 * @brief 计算字符串SHA-256
 *
 * @param str 字符串指针
 * @param length 字符串长度
 * @param sha256 用于保存SHA-256的字符串指针
 * @return int 成功返回0
 */
int  StrSha256(char* str, long length, char* sha256)
{
    mbedtls_sha256(str, length, sha256, 0);
    return 0;
}

int getLocalIp(const char * eth_name, char *local_ip_addr)
{
	int ret = -1;
#ifdef L0_DEVICE
    struct netif *lwipNetif = netifapi_netif_find_by_name(eth_name);
    uint32_t ip = lwipNetif->ip_addr->ip4_addr_t->addr;
    LOG_I("net_intf_status_change_cb **ip = %s\n", inet_ntoa(ip));
    memset(local_ip_addr, 0, IP_STR_LEN_MAX + 1);

#elif defined(L2_DEVICE)
    register int fd;
    struct ifreq ifr[32];
    struct ifconf ifc;
 
    if (local_ip_addr == NULL || eth_name == NULL)
	{
        return ret;
	}
	if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) > 0)
	{
		ifc.ifc_len = sizeof ifr;
		ifc.ifc_buf = (caddr_t)ifr;
		if (!ioctl(fd, SIOCGIFCONF, (char*)&ifc)) //获取所有接口信息
		{
			register int intrface = ifc.ifc_len / sizeof(struct ifreq);
			while (intrface-- > 0)
			{
				//Get IP Address
				if (!(ioctl(fd, SIOCGIFADDR, (char*)&ifr[intrface])))
				{
					if(strcmp(eth_name, ifr[intrface].ifr_name) == 0)
					{
						ret = 0;
						sprintf(local_ip_addr, "%s", inet_ntoa(((struct sockaddr_in*)(&ifr[intrface].ifr_addr))->sin_addr));
						break;
					}
				}
			}
		}
	}
	if (fd > 0)
	{
		close(fd);
	}
#endif
    return ret;
}

static int logFd = -1;
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

int initLogs(const char *logRoute)
{
  logFd = open(logRoute, O_CREAT | O_APPEND | O_RDWR);
  if (logFd < 0) {
      return -1;
  }
  return logFd;
}

int addLogs(const char *logs)
{
    if (logFd >= 0 && logs) {
        pthread_mutex_lock(&g_mutex);
        write(logFd, logs, strlen(logs));
        write(logFd, "\n", strlen("\n"));
        fsync(logFd);
        pthread_mutex_unlock(&g_mutex);
        return 0;
    }
    return -1;
}

u32 getMillionSecond(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}

int closeLogs(void)
{
    if (logFd >= 0) {
        pthread_mutex_lock(&g_mutex);
        close(logFd);
        logFd = -1;
        pthread_mutex_unlock(&g_mutex);
    }
    return 0;
}


#ifdef L2_DEVICE

MSG_QUEUE_ID local_queue_init(void)
{
    LocalQueInfo *queue = (LocalQueInfo *)malloc(sizeof(LocalQueInfo));
    if (queue == NULL) {
        addLogs("OOM! \r\n");
        return 0;
    }

    queue->key = 0;
    queue->msgQueue = msgget(queue->key, IPC_CREAT | 0666);
    if (queue->msgQueue < 0) {
        addLogs("msgget faild!");
        free(queue);
        return 0;
    }

    return (MSG_QUEUE_ID)queue;
}

int local_queue_put_udp(MSG_QUEUE_ID queue, const LocalNetUdpSendDataDef *data, int size)
{
    int ret = 0;
    if (queue == 0 || data == NULL || size <= 0) {
        addLogs("NULL POINT! \r\n");
        return -1;
    }
    LocalQueInfo *queueInfo = (LocalQueInfo *)queue;
    MsgInfo msgInfo = {0};
    msgInfo.type = 1;
    msgInfo.data = *data;

    if (msgsnd(queueInfo->msgQueue, (void *)&msgInfo, size, 0) < 0) {
        addLogs("msgsnd error: ");
        addLogs(strerror(errno));
        ret = -1;
    }

    return ret;
}

int local_queue_get_udp(MSG_QUEUE_ID queue, void *data, int size)
{
    if (queue == 0 || data == NULL || size <= 0) {
        addLogs("param is invalid! \r\n");
        return -1;
    }

    LocalQueInfo *queueInfo = (LocalQueInfo *)queue;
    MsgInfo msgInfo = {0};
    msgInfo.type = 1;

    if (msgrcv(queueInfo->msgQueue, &msgInfo, size, 0, 0) < 0) {
        addLogs("msgrcv error. \r\n");
        return -1;
    }

    memcpy(data, &(msgInfo.data), size);

    return 0;
}

void local_queue_deinit(MSG_QUEUE_ID queue)
{
    LocalQueInfo *queueInfo = (LocalQueInfo *)queue;
    if (queueInfo) {
        free(queueInfo);
    }
}


// 消息队列相关函数 —— local_net_comm
int local_queue_put_comm(MSG_QUEUE_ID queue, const LocalNetMsgRecv *data, int size)
{
    int ret = 0;
    if (queue == 0 || data == NULL || size <= 0) {
        addLogs("NULL POINT! \r\n");
        return -1;
    }
    LocalQueInfo *queueInfo = (LocalQueInfo *)queue;
    MsgInfoComm msgInfo = {0};
    msgInfo.type = 1;
    msgInfo.data = *data;

    if (msgsnd(queueInfo->msgQueue, (void *)&msgInfo, size, 0) < 0) {
        addLogs("msgsnd error: ");
        addLogs(strerror(errno));
        ret = -1;
    }

    return ret;
}

int local_queue_get_comm(MSG_QUEUE_ID queue, void *data, int size)
{
    if (queue == 0 || data == NULL || size <= 0) {
        addLogs("param is invalid! \r\n");
        return -1;
    }

    LocalQueInfo *queueInfo = (LocalQueInfo *)queue;
    MsgInfoComm msgInfo = {0};
    msgInfo.type = 1;

    if (msgrcv(queueInfo->msgQueue, &msgInfo, size, 0, 0) < 0) {
        addLogs("msgrcv error. \r\n");
        return -1;
    }

    memcpy(data, &(msgInfo.data), size);

    return 0;
}

#endif
